/**
 * @description  将文字转为SVG
 * @author Chorin <xiaolinxuan@foxmail.com>
 * @date 2020-05-05
 * @export
 * @class TextToSVG
 */
import * as opentype from 'opentype.js';
export default class TextToSVG{

  constructor(font) {
    this.font = font;
  }

  static load(url) {
    return new Promise((resolve, reject) =>{
      opentype.load(url, (error, font) =>{
        if(error){
          reject(error);
        }else{
          console.log("#### font", font);
          resolve(new TextToSVG(font));
        }
      });
    });
  }

  getWidth(text, options) {
    let fontSize = options.fontSize || 72;
    let kerning = 'kerning' in options ? options.kerning : true;
    let fontScale = 1 / this.font.unitsPerEm * fontSize;
    let width = 0;
    let glyphs = this.font.stringToGlyphs(text);
    for (let i = 0; i < glyphs.length; i++) {
      let glyph = glyphs[i];

      if (glyph.advanceWidth) {
        width += glyph.advanceWidth * fontScale;
      }

      if (kerning && i < glyphs.length - 1) {
        let kerningValue = this.font.getKerningValue(glyph, glyphs[i + 1]);
        width += kerningValue * fontScale;
      }

      if (options.letterSpacing) {
        width += options.letterSpacing * fontSize;
      } else if (options.tracking) {
        width += (options.tracking / 1000) * fontSize;
      }
    }
    return width;
  }

  getFontScale(fontSize){
    return 1000 / this.font.unitsPerEm * fontSize; /// 1 / this.font.unitsPerEm * fontSize;
  }

  getHeight(fontSize) {
    let fontScale = this.getFontScale(fontSize);
    return (this.font.ascender - this.font.descender) * fontScale;
  }

  getMetrics(text, options = {}) {
    let fontSize = options.fontSize || 72;
    let anchor = parseAnchorOption(options.anchor || '');

    let width = this.getWidth(text, options);
    let height = this.getHeight(fontSize);

    let fontScale = this.getFontScale(fontSize);
    let ascender = this.font.ascender * fontScale;
    let descender = this.font.descender * fontScale;

    let x = options.x || 0;
    switch (anchor.horizontal) {
      case 'left':
        x -= 0;
        break;
      case 'center':
        x -= width / 2;
        break;
      case 'right':
        x -= width;
        break;
      default:
        throw new Error(`Unknown anchor option: ${anchor.horizontal}`);
    }

    let y = options.y || fontSize ||0;
    switch (anchor.vertical) {
      case 'baseline':
        y -= ascender;
        break;
      case 'top':
        y -= 0;
        break;
      case 'middle':
        y += height / 2;   ///y -= height / 2;
        break;
      case 'bottom':
        y += height;      ///y -= height;
        break;
      default:
        throw new Error(`Unknown anchor option: ${anchor.vertical}`);
    }
  
    let baseline = height * (60 / 72);  ///let baseline = y + ascender;

    return {
      x,
      y,
      baseline,
      width,
      height,
      ascender,
      descender,
    };
  }

  getD(text, options = {}) {
    let fontSize = options.fontSize || 72;
    let kerning = 'kerning' in options ? options.kerning : true;
    let letterSpacing = 'letterSpacing' in options ? options.letterSpacing : false;
    let tracking = 'tracking' in options ? options.tracking : false;
    let metrics = this.getMetrics(text, options);
    let path = this.font.getPath(text, metrics.x, metrics.baseline, fontSize, { kerning, letterSpacing, tracking });

    return path.toPathData();
  }

  getPath(text, options = {}) {
    let attributes = Object.keys(options.attributes || {})
      .map(key => `${key}="${options.attributes[key]}"`)
      .join(' ');
    let d = this.getD(text, options);
    return `<path ${attributes || ''} d="${d}"/>`;
  }

  getSVG(text, options = {}) {
    let metrics = this.getMetrics(text, options);
    let svg = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${metrics.width}" height="${metrics.height}">`;
    svg += this.getPath(text, options);
    svg += '</svg>';

    return svg;
  }

  getDebugSVG(text, options = {}) {
    options = JSON.parse(JSON.stringify(options));
    options.x = options.x || 0;
    options.y = options.y || 0;
    let metrics = this.getMetrics(text, options);
    let box = {
      width: Math.max(metrics.x + metrics.width, 0) - Math.min(metrics.x, 0),
      height: Math.max(metrics.y + metrics.height, 0) - Math.min(metrics.y, 0),
    };
    let origin = {
      x: box.width - Math.max(metrics.x + metrics.width, 0),
      y: box.height - Math.max(metrics.y + metrics.height, 0),
    };

    // Shift text based on origin
    options.x += origin.x;
    options.y += origin.y;

    let svg = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${box.width}" height="${box.height}">`;
    svg += `<path fill="none" stroke="red" stroke-width="1" d="M0,${origin.y}L${box.width},${origin.y}"/>`; // X Axis
    svg += `<path fill="none" stroke="red" stroke-width="1" d="M${origin.x},0L${origin.x},${box.height}"/>`; // Y Axis
    svg += this.getPath(text, options);
    svg += '</svg>';
    return svg;
  }
}


function parseAnchorOption(anchor) {
  let horizontal = anchor.match(/left|center|right/gi) || [];
  horizontal = horizontal.length === 0 ? 'left' : horizontal[0];

  let vertical = anchor.match(/baseline|top|bottom|middle/gi) || [];
  vertical = vertical.length === 0 ? 'baseline' : vertical[0];

  return { horizontal, vertical };
}